#include"include/server.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/epoll.h>
#include "include/Login.h"
#include "include/common.h"
#include "include/thread.h"
#include "include/db.h"
#include <crypt.h>
#include "include/LogSystem.h"
#include "include/epoll.h"


int exitpipe[2];
//打开服务端0
int start_sever(char *ip,int port){
    int socketFd = socket(AF_INET,SOCK_STREAM,0);
    ERROR_CHECK(socketFd,-1,"socket");
    struct sockaddr_in addr = {0};
    struct in_addr ipAddr;
    inet_aton(ip,&ipAddr);
    int portNet = htons(port);
    addr.sin_family = AF_INET;
    addr.sin_addr = ipAddr;
    addr.sin_port = portNet;
    int bindRet = bind(socketFd,(struct sockaddr*)&addr,sizeof(addr));
    ERROR_CHECK(bindRet,-1,"bind");
    int listenRet = listen(socketFd,10);
    ERROR_CHECK(listenRet,-1,"listen");
    
    printf("Server listening on %s:%d...\n", ip, port);
    return socketFd;
}
//接受客户端响应
int accept_client(int server_fd,char *username){
    int client_fd = accept(server_fd,NULL,NULL);
    ERROR_CHECK(client_fd,-1,"accept");
    char name[64]={0},password[64]={0};
    send(client_fd, "Username:", 10, 0);
    recv(client_fd,name,sizeof(name),0);
    //send(client_fd, "Password:", 10, 0);
    //recv(client_fd,password,sizeof(password),0);
    sprintf(username,"%s",name);

    char salt[64] = {0}, encrypted_pass[256] = {0};
    if(db_get_user(name, salt, encrypted_pass) != 0){
        // 用户不存在，询问是否注册
        char regbuf[16] = {0};
        send(client_fd, "User not found. Type 'register' to create, or 'login' to retry:", 56, 0);
        recv(client_fd, regbuf, sizeof(regbuf), 0);
        if(strncmp(regbuf, "register", 8) == 0){
            // 注册流程
            send(client_fd, "Set password:", 14, 0);
            char newpass[64] = {0};
            recv(client_fd, newpass, sizeof(newpass), 0);
            // 生成 salt
            snprintf(salt, sizeof(salt), "$6$%08x$", rand()); // SHA-512 salt
            char *crypt_pass = crypt(newpass, salt);
            db_store_user(name, salt, crypt_pass);
            int flag_reg = PASSWORD_TRUE;
            send(client_fd, &flag_reg, sizeof(int), 0);
            return client_fd;
        } else {
            int flag_login = PASSWORD_ERROR;
            send(client_fd, &flag_login, sizeof(int), 0);
            close(client_fd);
            return -1;
        }
    }
    send(client_fd, "Password:", 10, 0);
    recv(client_fd,password,sizeof(password),0);
    // crypt 加密比对
    char *crypt_pass = crypt(password, salt);
    if(strcmp(crypt_pass, encrypted_pass) != 0){
        int flag_login = PASSWORD_ERROR;
        send(client_fd,&flag_login,sizeof(int),0);
        close(client_fd);
        return -1;
    }
    int flag_login = PASSWORD_TRUE;
    send(client_fd,&flag_login,sizeof(int),0);
    LOG_LOGIN(name);
    return client_fd;
}

void sigFunc(int signum){
    printf("signum = %d\n", signum);
    write(exitpipe[1],"1",1);
    puts("Parent exit!");
 }


int main(int argc,char *argv[]){

    if(argc!=4){
        fprintf(stderr,"Usage: %s <ip> <port> threadNum\n",argv[0]);
        exit(1);
    }
    int workerNum = atoi(argv[3]);
    //创建子进程用于构造和执行线程，主进程epoll监听网络管道和进程管道，收到关闭后向子进程发送关闭信号
    // int exitpipe[2];（q全局变量）
    pipe(exitpipe);
    if(fork()!=0){
        close(exitpipe[0]);
        signal(SIGUSR1,sigFunc);
        wait(NULL);
        exit(0);    
    }
    close(exitpipe[1]);
    
    //打开并监听服务器
    int server_fd = start_sever(argv[1],atoi(argv[2]));
    //建立任务队列并初始化
    threadPool_t threadPool;
    threadPoolInit(&threadPool,workerNum);
    makeWorker(&threadPool);
    //构造epoll监听网络管道和父子进程通信管道
    int epfd = epoll_create(1);
    if(epfd == -1){
        perror("epoll_create");
    }
    epollAdd(exitpipe[0],epfd);
    epollAdd(server_fd,epfd);
    struct epoll_event readylist[2];

    // 数据库初始化
    if(db_init("localhost", "root", "123456", "CloudProject") != 0){
        fprintf(stderr, "数据库连接失败！\n");
        exit(1);
    }
    //char usename[20]={0};
    while(1){
    //监听两个端口
    int readyNum = epoll_wait(epfd,readylist,2,-1);
        for(int i=0;i<readyNum;i++){
            if(readylist[i].data.fd == server_fd){
            //接受客户端连接
                pthread_mutex_lock(&threadPool.mutex);
                int netFd = accept_client(server_fd,&threadPool.username);
                if(netFd == -1){
                    perror("accept_client");
                    pthread_mutex_unlock(&threadPool.mutex);
                    continue;
                }
            //对队列的互斥访问
                taskEnqueue(&threadPool.taskQueue,netFd);
                pthread_cond_signal(&threadPool.cond);
                pthread_mutex_unlock(&threadPool.mutex);
            }
            else if(readylist[i].data.fd == exitpipe[0]){
                puts("exit threadPool!");
                pthread_mutex_lock(&threadPool.mutex);
                threadPool.destory_flag = true;
                pthread_cond_signal(&threadPool.cond);
                pthread_mutex_unlock(&threadPool.mutex);
                for(int j = 0; j < workerNum; ++j){
                    pthread_join(threadPool.pidArr[j],NULL);
                }
                puts("done");
                db_close(); // 关闭数据库
                exit(0);
            }
        }
    }

    return 0;
}